/***********************************************************************************
 * 文件名： soft_uart.h
 * 版本： 2
 * 说明：
 * 		软件模拟UART。提供单个字节发送和接收的基本功能，类似于常见MCU的基础UART外设。在头文
 *  件中查看 API 以及说明。
 * 修改记录：
 * 	2021/04/28: 初版。 刘言。
 *  2022/06/06: 新增同步模式；新增 _SUART_INIT_STATE 配置项；头文件包含优化。
***********************************************************************************/
#ifndef _SOFT_UART_H_
#define _SOFT_UART_H_

#include <stddef.h>
#ifdef __NO_INCLUDE_PATH    // 如果有，定义在 stddef.h
// 通过修改这里设置正确的配置头文件路径
#include "..\..\..\projects\prj\App\suart_config.h"
#else
#include "suart_config.h"
#endif

#include "..\..\polsys.h"

#ifndef _SUART_USE_SYNC_MODE
// SUART事件
typedef enum _suart_ev
{
    SUART_EV_NULL,
    SUART_EV_RX_DONE,   // 一个字节接收完毕，必须在一个位周期（3个定时器时钟周期）的时间内返回。
    SUART_EV_STOP_ERR,  // 停止位电平错误（如果SUart_Event处理时间大于3个时钟周期，导致接收停止位时已经达到了下一个起始位，也会导致这个错误），下一次的高电平将会认为是空闲状态
    SUART_EV_TX_DONE,   // 一个字节发送完毕
    _SUART_EV_END
}suart_ev_t;
#endif


// 为了伪函数代码优化暴露以下属性

#ifndef _SUART_USE_SYNC_MODE
extern bit _SUart_Run;
extern volatile u8 _SUart_mRxBuff;           // 接收缓存
extern volatile bit _SUart_mSending;
#endif

//////// API

#ifndef _SUART_USE_SYNC_MODE
// 定时器中断中调用，定时器中断频率的 1/3 就是波特率。
void SUart_EvTimer();

// 关闭 SUART，可以降低CPU占用率
#define SUart_Disable()     _SUart_Run = false

// 开启 SUART
#define SUart_Enable()      _SUart_Run = true

// 获取刚刚收到的一个字节，一般在收到 SUART_EV_RX_DONE 事件后调用。
#define SUart_GetRxByte()   _SUart_mRxBuff

// [异步]发送一个字节
// 发送完成后会触发 SUART_EV_TX_DONE 事件（如果使能），也可以调用 SUart_GetTxFlag 查询发送状态。
void SUart_SendByte(u8 one_byte);

// 获取（查询）发送状态
// 1：发送中，0：发送完毕
#define SUart_GetTxFlag()   _SUart_mSending
#else

/*
    接收一个字节，收到1个字节或者错误后返回，错误后返回0.
    调用本函数后将开始接收数据，直到收到数据或者设置的时间超时。你也可以在特定的IO口中断发生后调用本函数，
比如起始位的下降沿，或者一个表示即将发送数据的上升沿。
    注意：如果使用起始位的下降沿作为触发调用本函数，必须在起始位出现后的规定时间内调用本函数，这个时间是
位周期的1/3（波特率4800时 = 69us）。如果后续紧接着还有数据，也必须在位周期的1/3内再次调用本函数。参考的
实现方案是：
        1. 起始位低电平中断后立即循环调用本函数（允许间隔位周期的1/3时间），这个IO中断耗时将会非常长。
        2. 起始位低电平中断后立即在主程序中循环调用本函数，RTOS环境中可以利用线程同步机制。
        3. CPU空闲或者休眠，起始位的下降沿唤醒CPU后立即循环调用本函数。
*/
u8 SUart_ReceiveByte();

// 发送一个字节，发送完毕后返回。
void SUart_SendByte(u8 one_byte);

#endif

// 初始化。端口和定时器。注意没有使能，需要调用 SUart_Enable 后 SUart 才开始运行。
#define SUart_Init()    \
{\
    _SUart_InitPin();\
    _SUart_InitTimer();\
}

#endif
